/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_queue.h"

/* Get N Node From the List's Head. */
int		BList_GetN(_t_blist * pSrc, _t_blist * pDst, int num){
	_t_bnode * pNode;
	int 	i;

	/* Judge for Num, Fast Path */
	if(num > 1) {
		if(pSrc->count > num){
			/* Dst's Tail */
			pDst->prev->next	=
			pNode				= pSrc->next;
			pNode->prev			= pDst->prev;

			/* Perf ? */
			FAST_EX4_OP(i, (num-1), (pNode=pNode->next));

			/* Src's Head */
			pNode->next->prev	= (_t_bnode *)pSrc;
			pSrc->next			= pNode->next;
			pSrc->count			-= num;

			/* Dst's Tail */
			pNode->next	   		= (_t_bnode *)pDst;
			pDst->prev 			= pNode;
			pDst->count			+= num;
			return 0;
		}
		
		else if (pSrc->count == num){
			pDst->next->prev = pSrc->prev;
			pSrc->prev->next = pDst->next;
			pSrc->next->prev = (_t_bnode *)pDst;
			pDst->next		 = pSrc->next;
			
			pDst->count += pSrc->count; 
			pSrc->next	= 
			pSrc->prev	= (_t_bnode *)pSrc; 
			pSrc->count = 0;
			return 0;
		}
	}
	else if((num == 1) && (pSrc->count >= 1)){
		/* Get */
		pNode=pSrc->next;	pSrc->next=pNode->next;
		pNode->next->prev=(_t_bnode *)pSrc;
		--(pSrc->count);

		/* Add 2 T */
		pNode->prev=pDst->prev;	pNode->next=(_t_bnode *)pDst;
		pDst->prev->next=pNode;	pDst->prev=pNode;
		++(pDst->count);
		return 0;
	}
	return -1;
}


/* ===========================================================
** RSI Function: Ready-Stdby-Idle
*/
/* Trace Lvl */
static 	int 	_gTraceLvl_SRsi = TRACELVL_NORMAL;

int 	SRsi_SetTraceLvl(int lvl)
{
	int 	ret = -1;
	
	switch(lvl){
		case TRACELVL_FATAL:
		case TRACELVL_ERROR:
		case TRACELVL_WARNING:
		case TRACELVL_NORMAL:
		case TRACELVL_DEBUG:
		case TRACELVL_ALL:
			_gTraceLvl_SRsi = lvl;
			ret = 0;
			break;
		default:
			break;
	}

	return ret;
}

int 	SRsi_GetTraceLvl(void)
{
	return  _gTraceLvl_SRsi;
}


int 	RSI_InitNode(_t_rsiNode * pNode)
{
	pNode->state 	= _RSI_IDLE;
	pNode->waken	= _F_NO;
	return 0;
}

int 	RSI_InitQue(_t_rsiQue * pRSI, _t_sysCS * pLock)
{
	BLIST_INIT(&(pRSI->ready));
	BLIST_INIT(&(pRSI->stdby));
	pRSI->pLock = pLock;
	return 0;
}

int  	RSI_DeQue(_t_rsiQue * pRSI, _t_rsiNode * pNode)
{
	SYS_ENTER_CS((pRSI->pLock));
	pNode->waken = _F_NO;
	switch(pNode->state){
		case _RSI_STDBY:
			pNode->state = _RSI_IDLE;
			BLST_DEL(&(pRSI->stdby), &(pNode->node));
			break;
			
		case _RSI_READY:
			pNode->state = _RSI_IDLE;
			BLST_DEL(&(pRSI->ready), &(pNode->node));
			break;
		
		case _RSI_IDLE:
		default:
			break;
	}
	SYS_LEAVE_CS((pRSI->pLock));
	
	return 0;
}


static __inline int  	RSI_EnQue(_t_rsiQue * pRSI, _t_rsiNode * pNode)
{
	switch(pNode->state){
		case _RSI_IDLE:
			if(pNode->waken == _F_YES){
				pNode->state = _RSI_READY;
				BLST_ADD2T(&(pRSI->ready), &(pNode->node));
			}else{
				pNode->state = _RSI_STDBY;
				BLST_ADD2T(&(pRSI->stdby), &(pNode->node));
			}
			break;
			
		case _RSI_STDBY:
			if(pNode->waken == _F_YES){
				pNode->state = _RSI_READY;
				BLST_DEL(&(pRSI->stdby), &(pNode->node));
				BLST_ADD2T(&(pRSI->ready), &(pNode->node));
			}
			break;

			
		case _RSI_READY:
			if(pNode->waken == _F_NO){
				pNode->state = _RSI_STDBY;
				BLST_DEL( &(pRSI->ready), 	&(pNode->node));
				BLST_ADD2T(&(pRSI->stdby), 	&(pNode->node));
			}
			break;
		
		default:
			break;
	}
	
	return 0;
}


int  	RSI_EnReady(_t_rsiQue * pRSI, _t_rsiNode * pNode)
{
	SYS_ENTER_CS((pRSI->pLock));
	pNode->waken = _F_YES;
	RSI_EnQue(pRSI, pNode);
	SYS_LEAVE_CS((pRSI->pLock));

	return 0;
}

int  	RSI_EnStdby(_t_rsiQue * pRSI, _t_rsiNode * pNode)
{
	SYS_ENTER_CS((pRSI->pLock));
	pNode->waken = _F_NO;
	RSI_EnQue(pRSI, pNode);
	SYS_LEAVE_CS((pRSI->pLock));

	return 0;
}


int 	RSI_XfStdby(_t_rsiQue * pRSI, int  xfCnt)
{
	int 				i, count;
	_t_rsiNode		* 	pNode;
	_t_rsiNode		* 	pNext;
	_t_blist 		* 	pQue;
	
	SYS_ENTER_CS((pRSI->pLock));
	pQue	= &(pRSI->stdby);	
	count	= pQue->count;
	SYS_TRACE(_gTraceLvl_SRsi, TRACELVL_DEBUG, "Rsi(%p): %-4d -> %-4d \n", 
				pRSI, count, xfCnt); 
	if((count > 0) && (xfCnt > 0)){
		if(count > xfCnt)
			count = xfCnt;

		pNode = (_t_rsiNode *)(pQue->head);
		for(i=0; i < count; i++, pNode=pNext){
			pNext	= (_t_rsiNode *)(pNode->node.next);
			pNode->waken= _F_YES;
			RSI_EnQue(pRSI, pNode);
		}
	}
	SYS_LEAVE_CS((pRSI->pLock));
	
	return 0;
}


int 	RSI_XfReady(_t_rsiQue * pRSI, int  xfCnt, int (*proc)())
{
	int 				i, count;
	_t_rsiNode		* 	pNode;
	_t_rsiNode		* 	pNext;
	_t_blist 		* 	pQue;

	count = 0;
	
	SYS_ENTER_CS((pRSI->pLock));
	pQue	= &(pRSI->ready);	
	count	= pQue->count;
	SYS_TRACE(_gTraceLvl_SRsi, TRACELVL_DEBUG, "Rsi(%p): %-4d -> %-4d \n", 
				pRSI, count, xfCnt); 
	if((count > 0) && (xfCnt > 0) && (proc)){
		if(count > xfCnt)
			count = xfCnt;

		pNode = (_t_rsiNode *)(pQue->head);
		for(i=0; i < count; i++, pNode=pNext){
			pNext	= (_t_rsiNode *)(pNode->node.next);
			/* Here we Bubble It :( */
			BLST_BUBBLE2T(pQue, &(pNode->node));
			/* Process */
			proc(pNode);
		}

		if(pQue->count > 0)
			count = 1;
	}
	SYS_LEAVE_CS((pRSI->pLock));

	return count;
}

